﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace LiveFrameworkExplorer.Plugins.LiveFxBrowser
{
    public partial class ucBrowser : UserControl
    {
        #region Private fields

        private ILFEBase _lfeBase;
        private Stack<Uri> navBackward;
        private Stack<Uri> navForward;
        private bool isProcessingRequest = false;
        private delegate void GoDelegate(Uri url);

        #endregion

        #region Public

        public ucBrowser()
        {
            InitializeComponent();
            this.tscbFormat.SelectedIndex = 0;
            this.tsbBack.Enabled = false;
            this.tsbForward.Enabled = false;
        }

        public void SetParameters(ILFEBase lfeBase, Uri url)
        {
            _lfeBase = lfeBase;
            navBackward = new Stack<Uri>();
            navForward = new Stack<Uri>();
            this.tscbUrl.Text = url.ToString();
            Go(url);
        }

        #endregion

        #region Private

        private string GetContentTypeHeader(string format)
        {
            switch (format.ToLower())
            {
                case "rss":
                    return "application/rss+xml";
                case "pox":
                    return "text/xml";
                case "json":
                    return "application/json";
                case "atom":
                    return "application/atom+xml";
                default:
                    return "";
            }
        }

        private void Go(Uri url)
        { Go(url, true); }
        private void Go(Uri url, bool markHistory)
        {
            if (isProcessingRequest)
                return;
            isProcessingRequest = true;
            if (markHistory)
            {
                if (navBackward.Count == 0 || (navBackward.Count > 0 && navBackward.Peek() != url))
                {
                    navBackward.Push(url);
                    if(!tscbUrl.Items.Contains(url.ToString()))
                        tscbUrl.Items.Add(url.ToString());
                }
                this.tsbBack.Enabled = navBackward.Count > 1;
                this.tsbForward.Enabled = navForward.Count > 0;
            }
            tscbUrl.Text = url.ToString();
            NavEntry entry = new NavEntry(url);
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            entry.webRequest = request;
            request.Accept = request.ContentType = GetContentTypeHeader(this.tscbFormat.SelectedItem as String);
            if (url.Host.Equals("localhost", StringComparison.InvariantCultureIgnoreCase))
            {
                string localAuthToken = LiveMeshLocal.GetLocalAuthToken(LiveMeshLocal.GetLocalServiceUri().ToString());
                if (!string.IsNullOrEmpty(localAuthToken))
                    request.Headers.Add("LiveFX-Local-Authenticator", localAuthToken);
            }
            else
            {
                string authToken = _lfeBase.GetLiveMeshAuthentificationToken();
                if (!string.IsNullOrEmpty(authToken))
                    request.Headers.Add(HttpRequestHeader.Authorization, authToken);
            }
            var statusBar = _lfeBase.GetDTEEnvironment().StatusBar;
            statusBar.Progress(true, "Download starting... " + entry.uri.AbsoluteUri, 1, 5);
            request.BeginGetResponse(new AsyncCallback(this.wc_DownloadDataCompletedProxy), entry);
        }

        private void wc_DownloadDataCompleted(IAsyncResult ar)
        {
            NavEntry asyncState = ar.AsyncState as NavEntry;
            try
            {
                if (!ar.IsCompleted)
                {
                    asyncState.htmlBody = LiveFxBrowserHelper.FormatTextAsHtml("Error: Request was cancelled", false);
                    asyncState.statusBarText = "Request was cancelled";
                }
                else
                {
                    HttpWebResponse response = null;
                    try
                    {
                        response = asyncState.webRequest.EndGetResponse(ar) as HttpWebResponse;
                    }
                    catch (WebException exception)
                    {
                        response = exception.Response as HttpWebResponse;
                        asyncState.statusBarText = "Error: " + exception.Status;
                        _lfeBase.WriteToLFEOutput("Error: " + exception.Status);
                    }
                    catch (Exception exception2)
                    {
                        asyncState.htmlBody = LiveFxBrowserHelper.FormatTextAsHtml("Exception processing request.  Details: \r\n\r\n" + exception2.ToString(), false);
                        asyncState.statusBarText = "Error";
                        _lfeBase.WriteToLFEOutput("Error: " + exception2.Message);
                    }
                    if (response != null)
                    {
                        asyncState.webResponse = response;
                        asyncState.contentLength = response.ContentLength;
                        asyncState.statusBarText = string.Format("Done.  ({0} bytes, HTTP status: {1})", asyncState.contentLength, response.StatusCode.ToString());
                        if ((response.ContentType != null) && ((response.ContentType.Contains("application/atomsvc+xml") || response.ContentType.Contains("application/atom+xml")) || (response.ContentType.Contains("text/xml") || response.ContentType.Contains("application/rss+xml"))))
                        {
                            List<string> list;
                            XmlDocument xd = new XmlDocument();
                            xd.Load(response.GetResponseStream());
                            StringWriter w = new StringWriter();
                            XmlTextWriter writer2 = new XmlTextWriter(w);
                            writer2.Formatting = Formatting.Indented;
                            string tag = "XXX{0}XXX";
                            LiveFxBrowserHelper.TagWlcResources(xd, tag, out list);
                            xd.DocumentElement.WriteTo(writer2);
                            string str2 = LiveFxBrowserHelper.ReplaceTagsWithMarkup(LiveFxBrowserHelper.FormatTextAsHtml(w.ToString(), false), tag, list);
                            asyncState.htmlBody = str2;
                        }
                        else if (response.ContentType == "application/json")
                        {
                            string json = new StreamReader(response.GetResponseStream(), Encoding.UTF8).ReadToEnd();
                            int start = 0;
                            if (json[start] > '\x00ff')
                            {
                                start++;
                            }
                            JsonItem item = JsonItem.Load(json, start);
                            List<string> markup = new List<string>();
                            string str4 = "XXX{0}XXX";
                            LiveFxBrowserHelper.TagWlcResources(item, str4, ref markup, asyncState.uri);
                            string str6 = LiveFxBrowserHelper.ReplaceTagsWithMarkup(LiveFxBrowserHelper.FormatTextAsHtml(item.ToFormattedString(4), false), str4, markup);
                            asyncState.htmlBody = str6;
                        }
                        else
                        {
                            StreamReader reader2 = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                            StringBuilder builder = new StringBuilder();
                            builder.Append("Status: " + response.StatusCode + "\r\n\r\nContent:\r\n\r\n");
                            builder.Append(reader2.ReadToEnd());
                            asyncState.htmlBody = LiveFxBrowserHelper.FormatTextAsHtml(builder.ToString(), false);
                        }
                    }
                }
            }
            catch (Exception exception3)
            {
                asyncState.htmlBody = LiveFxBrowserHelper.FormatTextAsHtml("Error: Unexpected exception processing result.  Details:\r\n\r\n" + exception3.ToString(), false);
            }
            finally
            {
                isProcessingRequest = false;
            }
            DisplayNavEntry(asyncState);
        }

        private void DisplayNavEntry(NavEntry entry)
        {
            var statusBar = _lfeBase.GetDTEEnvironment().StatusBar;
            this.tscbUrl.Text = entry.uri.AbsoluteUri;
            statusBar.Progress(false, entry.statusBarText, 5, 5);
            webBrowser1.DocumentText = entry.htmlBody;
        }

        private void wc_DownloadDataCompletedProxy(IAsyncResult ar)
        {
            try
            {
                AsyncCallback method = new AsyncCallback(this.wc_DownloadDataCompleted);
                object[] args = new object[] { ar };
                base.BeginInvoke(method, args);
            }
            catch { }
        }

        #endregion

        #region Control's events

        private void tsbBack_Click(object sender, EventArgs e)
        {
            if (navBackward.Count > 1)
            {
                Uri item = navBackward.Pop();
                if (navBackward.Count == 1)
                {
                    tsbBack.Enabled = false;
                }
                navForward.Push(item);
                tsbForward.Enabled = true;
                Go(navBackward.Peek(), false);
            }

        }

        private void tsbForward_Click(object sender, EventArgs e)
        {
            if (navBackward.Count > 0)
            {
                Uri item = navForward.Pop();
                if (navForward.Count == 0)
                {
                    tsbForward.Enabled = false;
                }
                navBackward.Push(item);
                tsbBack.Enabled = true;
                Go(item, false);
            }
        }

        private void tsbRefresh_Click(object sender, EventArgs e)
        {
            if (navBackward.Count > 0)
            {
                Go(navBackward.Peek(), false);
            }
            webBrowser1.Focus();
            webBrowser1.Select();
        }

        private void tscbFormat_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(navBackward != null)
                tsbRefresh_Click(sender, e);
        }

        private void tscbUrl_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                tsbGo_Click(sender, e);
        }

        private void tsbGo_Click(object sender, EventArgs e)
        {
            try
            {
                Go(new Uri(tscbUrl.Text));
            }
            catch (Exception)
            {
                MessageBox.Show("Invalid URL !", "Live Framework Explorer", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            if (e.Url.AbsoluteUri != "about:blank")
            {
                e.Cancel = true;
                base.BeginInvoke(new GoDelegate(Go), new object[] { e.Url });
            }
        }

        private void toolStrip2_Layout(object sender, LayoutEventArgs e)
        {
            this.tscbUrl.Width = (toolStrip2.Width -
                (toolStripLabel2.Width + toolStripLabel2.Margin.Horizontal + tsbGo.Width + tsbGo.Margin.Horizontal + 10));
            this.tscbUrl.DropDownWidth = this.tscbUrl.Width;
        }

        #endregion
    }
}